<?php
/**
 * Created by PhpStorm.
 * User: xuhon
 * Date: 2016/11/22
 * Time: 17:12
 */
class PDOX
{
    protected static $_instance = null;
    protected $dbName = '';
    protected $dsn;
    public $pdo;
    public $pdos = array();

    /**
     * 构造
     *
     * @return PDOX
     */
    private function __construct($dsn, $dbUser, $dbPasswd, $dbCharset)
    {
        try {
            if (is_array($dsn)) {
                foreach ($dsn as $db) {
                    $this->pdos[] = new PDO($db, $dbUser, $dbPasswd);
                }
            } else {
                $this->pdos[] = new PDO($dsn, $dbUser, $dbPasswd);
            }
            $this->setDSN();
            
            $this->pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
            $this->pdo->exec('SET character_set_connection='.$dbCharset.', character_set_results='.$dbCharset.', character_set_client=binary');
        } catch (PDOException $e) {
            $this->outputError($e->getMessage());
        }
    }

    /**
     * 防止克隆
     *
     */
    private function __clone() {}

    /**
     * Singleton instance
     * @return Object
     */
    public static function getInstance($dsn, $dbUser, $dbPasswd, $dbCharset)
    {
        if (self::$_instance === null) {
            self::$_instance = new self($dsn, $dbUser, $dbPasswd, $dbCharset);
        }
        return self::$_instance;
    }
    
    //指定使用数据库组里面哪个数据库
    public function setDSN($index=0){
        if (count($this->pdos)<=$index) return;
        $this->pdo = $this->pdos[$index];
    }

    /**
     * Query 查询
     *
     * @param String $sql SQL语句
     * @param String $queryMode 查询方式(All or Row)
     * @param Boolean $debug
     * @return Array
     */
    function query($sql, $queryMode = 'All', $debug = false) {
        if ($debug === true) $this->debug($sql);
        $recordset = $this->pdo->query($sql);
        $this->getPDOError();
        if ($recordset) {
            $recordset->setFetchMode(PDO::FETCH_ASSOC);
            if ($queryMode == 'All') {
                $result = $recordset->fetchAll();
            } elseif ($queryMode == 'Row') {
                $result = $recordset->fetch();
            }
        } else {
            $result = NULL;
        }
        return $result;
    }
    //执行各种 sql 指令,防注入
    function query_bind($sql,$param=array(),$queryMode = 'All', $debug = false,$sign="normal") {
        if ($debug === true) $this->debug($sql);
        $recordset = $this->pdo->prepare($sql);
        $this->getPDOError();
        $result=NULL;
        if(is_array($param) && count($param)){
            foreach ($param as $key=>$item) {
                if(is_int($key)){
                    $recordset->bindParam($key+1,$param[$key]);
                }
                else{
                    $recordset->bindParam($key,$param[$key]);
                }
            }
        }
        if ($recordset) {
            $recordset->setFetchMode(PDO::FETCH_ASSOC);
            $r= $recordset->execute();
            if($sign=="normal"){
                if ($queryMode == 'All') {
                    return $recordset->fetchAll();
                } elseif ($queryMode == 'Row') {
                    return $recordset->fetch();
                }
            }
            elseif($sign=='insert'){
                return $this->pdo->lastInsertId();
            }
            elseif($sign=="update"){
                return $r;
            }
        }
        return $result;
    }

    //查询并返回单条记录
    function get_row($sql,$debug=false,$output='OBJECT') {
        if($output=='OBJECT'){
            $result=new stdClass();
            $obj=$this->query($sql,'Row',$debug);
            if($obj){
                foreach ( $obj as $key=> $item) {
                    $result->$key=$item;
                }
            }else{
                $result=NULL;
            }
            return $result;
        }
        else{
            return $this->query($sql,'Row',$debug);
        }
    }

    //查询并返回单条记录,防注入
    function get_row_bind($sql,$param=array(),$debug=false,$output='OBJECT') {
        if($output=='OBJECT'){
            $result=new stdClass();
            $obj=$this->query_bind($sql,$param,'Row',$debug);
            if($obj){
                foreach ($obj  as $key=> $item) {
                    $result->$key=$item;
                }
            }else{
                $result=NULL;
            }
            return $result;
        }
        else{
            return $this->query_bind($sql,$param,'Row',$debug);
        }
    }

    //查询并以数组方式返回多条记录
    function get_results($sql,$output = 'OBJECT') {
        if($output=='OBJECT'){
            $results=array();
            $rs=$this->query($sql);
            if($rs){
                foreach ($rs as $item) {
                    $result=new stdClass();
                    foreach($item as $key=>$value){
                        $result->$key=$value;
                    }
                    $results[]=$result;
                }
            }else{
                $result=NULL;
            }
            return $results;
        }
        else{
            return $this->query($sql);
        }
    }

    //查询并以数组方式返回多条记录,防注入
    function get_results_bind($sql,$param=array(),$output = 'OBJECT') {
        if($output=='OBJECT'){
            $results=array();
            $rs=$this->query_bind($sql,$param);
            if($rs){
                foreach ($rs as $item) {
                    $result=new stdClass();
                    foreach($item as $key=>$value){
                        $result->$key=$value;
                    }
                    $results[]=$result;
                }
            }else{
                $result=NULL;
            }
            return $results;
        }
        else{
            return $this->query_bind($sql,$param);
        }
    }

    function get_var($sql,$debug=false){
        $rs= $this->query_bind($sql,'Row',$debug);
        $var = array(0);
        if(count($rs)>0)$var = array_values($rs);
        return $var[0];
    }

    function get_var_bind($sql,$param=array(),$debug=false){
        $rs= $this->query_bind($sql,$param,'Row',$debug);
        $var = array(0);
        if($rs && count($rs)>0)$var = array_values($rs);
        return $var[0];
    }

    /**
     * debug
     * @param mixed $debuginfo
     */
    private function debug($debuginfo)
    {
        var_dump($debuginfo);
        exit();
    }

    /**
     * getPDOError 捕获PDO错误信息
     */
    private function getPDOError()
    {
        if ($this->pdo->errorCode() != '00000') {
            $arrayError = $this->pdo->errorInfo();
            if($this->pdo->inTransaction()) $this->rollBack();
            $this->outputError($arrayError[2]);
        }
    }

    public function beginTransaction(){
        if(!$this->pdo->inTransaction()) {
            $this->pdo->beginTransaction();
        }
    }

    /**
     * @return bool
     */
    public function inTransaction(){
        return $this->pdo->inTransaction();
    }

    public function commitTransaction(){
        if($this->pdo->inTransaction()) {
            $this->pdo->commit();
        }
    }

    public function rollBack(){
        if($this->pdo->inTransaction()){
            $this->pdo->rollBack();
        }
    }

    /**
     * 输出错误信息
     * @param String $strErrMsg
     * @throws Exception
     */
    public function outputError($strErrMsg)
    {
        throw new RuntimeException('MySQL Error: '.$strErrMsg);
    }

    public function get_insert_id(){
        return $this->pdo->lastInsertId();
    }
}